// Package user_service_v1
// @Author zhongxc
// @Date 2024/7/23 15:37:00
// @Desc
package user_service_v1

import (
	"context"
	"fmt"
	"github.com/google/uuid"
	"github.com/jinzhu/copier"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"strings"
	"time"
	"vben-admin/pkg/dao"
	"vben-admin/pkg/model"
	"vben-admin/pkg/repository"
	"vben-admin/pkg/svc"
	"vben-common/utils"
	userServiceV1 "vben-grpc-common/vben-admin/types/user.service.v1"
)

type UserService struct {
	userServiceV1.UnimplementedUserServiceServer
	svcCtx  *svc.ServiceContext
	userDao repository.UserRepo
}

func NewUserService(svcCtx *svc.ServiceContext) *UserService {
	return &UserService{
		svcCtx:  svcCtx,
		userDao: dao.NewUserDao(svcCtx.Db),
	}
}

// CreateUser
// @Description: 创建用户
// @receiver u
// @param ctx
// @param in
// @return *emptypb.Empty
// @return error
func (u *UserService) CreateUser(ctx context.Context, in *userServiceV1.CreateUserRequest) (*emptypb.Empty, error) {
	// 参数校验
	if strings.TrimSpace(in.Username) == "" {
		return nil, status.Error(codes.InvalidArgument, "用户名不能为空")
	}

	if strings.TrimSpace(in.Password) == "" {
		return nil, status.Error(codes.InvalidArgument, "密码不能为空")
	}

	// 验证用户名是否重复
	if user, err := u.userDao.FindByName(ctx, in.Username); err != nil {
		return nil, status.Error(codes.Internal, "创建用户失败")
	} else if user != nil {
		return nil, status.Error(codes.AlreadyExists, "用户名已存在")
	}

	// 验证手机号是否重复
	if user, err := u.userDao.FindByMobile(ctx, in.Mobile); err != nil {
		return nil, status.Error(codes.Internal, "创建用户失败")
	} else if user != nil {
		return nil, status.Error(codes.AlreadyExists, "一个手机号只能绑定一个用户")
	}

	// 参数组装
	var user model.UserModel
	_ = copier.Copy(&user, in)

	user.Salt = uuid.New().String()
	user.Password = utils.Base64Md5(user.Password + user.Salt)
	user.Status = model.StatusEnable
	user.CreatedAt.Time = time.Now()
	user.CreatedAt.Valid = true

	err := u.userDao.CreateUser(ctx, &user)
	if err != nil {
		return nil, status.Error(codes.Internal, "创建用户失败")
	}

	// TODO 关联角色
	// ...

	return &emptypb.Empty{}, nil
}

// UpdateUser
// @Description: 更新用户信息
// @receiver u
// @param ctx
// @param in
// @return *emptypb.Empty
// @return error
func (u *UserService) UpdateUser(ctx context.Context, in *userServiceV1.UpdateUserRequest) (*emptypb.Empty, error) {
	if in.Id == 0 {
		return nil, status.Error(codes.InvalidArgument, "id不能为空")
	}
	if strings.TrimSpace(in.Username) == "" {
		return nil, status.Error(codes.InvalidArgument, "用户名不能为空")
	}
	if strings.TrimSpace(in.Mobile) == "" {
		return nil, status.Error(codes.InvalidArgument, "手机号不能为空")
	}
	if in.Status != model.StatusEnable && in.Status != model.StatusDisable {
		return nil, status.Error(codes.InvalidArgument, "状态非法")
	}

	// 验证用户名是否重复
	if user, err := u.userDao.FindByName(ctx, in.Username); err != nil {
		return nil, status.Error(codes.Internal, "创建用户失败")
	} else if user != nil && user.Id != in.Id {
		return nil, status.Error(codes.AlreadyExists, "用户名已存在")
	}

	// 验证手机号是否重复
	if user, err := u.userDao.FindByMobile(ctx, in.Mobile); err != nil {
		return nil, status.Error(codes.Internal, "创建用户失败")
	} else if user != nil && user.Mobile != in.Mobile {
		return nil, status.Error(codes.AlreadyExists, "一个手机号只能绑定一个用户")
	}

	var userMap = make(map[string]interface{})
	userMap["nickname"] = in.Nickname
	userMap["username"] = in.Username
	userMap["avatar"] = in.Avatar
	userMap["email"] = in.Email
	userMap["mobile"] = in.Mobile
	userMap["remark"] = in.Remark
	userMap["status"] = in.Status
	userMap["role_id"] = in.RoleId
	userMap["dept_id"] = in.DeptId
	userMap["updated_by"] = in.UpdatedBy
	userMap["updated_at"] = time.Now()

	err := u.userDao.UpdateUserById(ctx, in.Id, userMap)
	if err != nil {
		return nil, status.Error(codes.Internal, "更新用户失败")
	}
	return nil, nil
}

// GetUserInfo
// @Description: 获取用户信息
// @receiver u
// @param ctx
// @param in
// @return *userServiceV1.UserResponse
// @return error
func (u *UserService) GetUserInfo(ctx context.Context, in *userServiceV1.GetUserRequest) (*userServiceV1.UserResponse, error) {
	if in.Id == 0 {
		return nil, status.Error(codes.InvalidArgument, "id不能为空")
	}

	userInfo, err := u.userDao.FindById(ctx, in.Id)
	if err != nil {
		u.svcCtx.ZapLog.Error(fmt.Sprintf("获取用户信息失败, err: %v", err))
		return nil, status.Error(codes.Internal, "获取用户信息失败")
	}

	if userInfo == nil {
		return nil, status.Error(codes.NotFound, "用户不存在")
	}

	createdAt := ""
	if userInfo.CreatedAt.Valid && !userInfo.CreatedAt.Time.IsZero() {
		createdAt = userInfo.CreatedAt.Time.Format(time.DateTime)
	}
	updateAt := ""
	if userInfo.UpdatedAt.Valid && !userInfo.UpdatedAt.Time.IsZero() {
		updateAt = userInfo.UpdatedAt.Time.Format(time.DateTime)
	}
	return &userServiceV1.UserResponse{
		Id:        userInfo.Id,
		Username:  userInfo.Username,
		Nickname:  userInfo.Nickname,
		Avatar:    userInfo.Avatar,
		Email:     userInfo.Email,
		Mobile:    userInfo.Mobile,
		Remark:    userInfo.Remark,
		Status:    userInfo.Status,
		CreatedBy: userInfo.CreatedBy,
		CreatedAt: createdAt,
		UpdatedBy: userInfo.UpdatedBy,
		UpdatedAt: updateAt,
	}, nil
}

// DeleteUser
// @Description: 删除用户
// @receiver u
// @param ctx
// @param in
// @return *emptypb.Empty
// @return error
func (u *UserService) DeleteUser(ctx context.Context, in *userServiceV1.DeleteUserRequest) (*emptypb.Empty, error) {
	if len(in.Ids) == 0 {
		return nil, status.Error(codes.InvalidArgument, "id不能为空")
	}
	if strings.TrimSpace(in.DeletedBy) == "" {
		return nil, status.Error(codes.InvalidArgument, "删除操作人不能为空")
	}
	err := u.userDao.BatchDeleteById(ctx, in.Ids, map[string]interface{}{
		"deleted":    1,
		"deleted_by": in.DeletedBy,
		"deleted_at": time.Now(),
	})
	if err != nil {
		u.svcCtx.ZapLog.Error(fmt.Sprintf("删除用户失败, err: %v", err))
		return nil, status.Error(codes.Internal, "角色删除失败")
	}
	return &emptypb.Empty{}, nil
}

// GetUserList
// @Description: 用户列表
// @receiver u
// @param ctx
// @param in
// @return *userServiceV1.UserListResponse
// @return error
func (u *UserService) GetUserList(ctx context.Context, in *userServiceV1.UserListRequest) (*userServiceV1.UserListResponse, error) {
	if in.Page == 0 {
		in.Page = 1
	}
	if in.Page > 100 {
		in.Page = 100
	}
	if in.PageSize == 0 {
		in.PageSize = 10
	}
	if in.PageSize > 100 {
		in.PageSize = 100
	}

	list, err := u.userDao.GetUserList(ctx, in.Username, in.Status, in.DeptId, in.Page, in.PageSize)
	if err != nil {
		u.svcCtx.ZapLog.Error(fmt.Sprintf("获取用户列表失败, err: %v", err))
		return nil, status.Error(codes.Internal, "获取用户列表失败")
	}

	var userData = make([]*userServiceV1.UserData, 0)
	for _, user := range list["data"].([]*model.UserQueryModel) {
		createdAt := ""
		if user.CreatedAt.Valid == true && !user.CreatedAt.Time.IsZero() {
			createdAt = user.CreatedAt.Time.Format(time.DateTime)
		}
		updateAt := ""
		if user.UpdatedAt.Valid && !user.UpdatedAt.Time.IsZero() {
			updateAt = user.UpdatedAt.Time.Format(time.DateTime)
		}
		userData = append(userData, &userServiceV1.UserData{
			Id:        user.Id,
			Username:  user.Username,
			Nickname:  user.Nickname,
			Avatar:    user.Avatar,
			Email:     user.Email,
			Mobile:    user.Mobile,
			Remark:    user.Remark,
			Status:    user.Status,
			CreatedBy: user.CreatedBy,
			CreatedAt: createdAt,
			UpdatedBy: user.UpdatedBy,
			UpdatedAt: updateAt,
			DeptId:    user.DeptId,
			RoleId:    user.RoleId,
			DeptName:  user.DeptName,
			RoleName:  user.RoleName,
		})
	}
	return &userServiceV1.UserListResponse{
		TotalCount: list["totalCount"].(int64),
		Page:       list["page"].(int64),
		TotalPage:  list["totalPage"].(int64),
		Limit:      list["pageSize"].(int64),
		Data:       userData,
	}, nil
}

// ChangePassword
// @Description: 修改密码
// @receiver u
// @param ctx
// @param in
// @return *emptypb.Empty
// @return error
func (u *UserService) ChangePassword(ctx context.Context, in *userServiceV1.ChangePasswordRequest) (*emptypb.Empty, error) {

	if strings.TrimSpace(in.UserName) == "" {
		return nil, status.Error(codes.InvalidArgument, "用户名不能为空")
	}

	if strings.TrimSpace(in.OldPassword) == "" {
		return nil, status.Error(codes.InvalidArgument, "旧密码不能为空")
	}

	if strings.TrimSpace(in.NewPassword) == "" {
		return nil, status.Error(codes.InvalidArgument, "新密码不能为空")
	}

	if strings.TrimSpace(in.ConfirmPassword) == "" {
		return nil, status.Error(codes.InvalidArgument, "确认密码不能为空")
	}

	if in.NewPassword != in.ConfirmPassword {
		return nil, status.Error(codes.InvalidArgument, "两次密码不一致")
	}

	user, err := u.userDao.FindByName(ctx, in.UserName)
	if err != nil {
		return nil, status.Error(codes.Internal, "获取用户出现异常了")
	}

	if user == nil {
		return nil, status.Error(codes.InvalidArgument, "用户不存在")
	}

	if user.Password != utils.Base64Md5(in.OldPassword+user.Salt) {
		return nil, status.Error(codes.InvalidArgument, "旧密码不正确")
	}

	err = u.userDao.UpdateUserById(ctx, user.Id, map[string]interface{}{
		"password":   utils.Base64Md5(in.NewPassword + user.Salt),
		"updated_at": time.Now(),
	})
	if err != nil {
		u.svcCtx.ZapLog.Error(fmt.Sprintf("修改密码失败, err: %v", err))
		return nil, status.Error(codes.Internal, "修改密码失败")
	}

	return &emptypb.Empty{}, nil
}

// ResetPassword
// @Description: 重置密码
// @receiver u
// @param ctx
// @param in
// @return *emptypb.Empty
// @return error
func (u *UserService) ResetPassword(ctx context.Context, in *userServiceV1.ResetPasswordRequest) (*emptypb.Empty, error) {

	if strings.TrimSpace(in.UserName) == "" {
		return nil, status.Error(codes.InvalidArgument, "用户名不能为空")
	}

	if strings.TrimSpace(in.NewPassword) == "" {
		return nil, status.Error(codes.InvalidArgument, "新密码不能为空")
	}

	user, err := u.userDao.FindByName(ctx, in.UserName)
	if err != nil {
		u.svcCtx.ZapLog.Error(fmt.Sprintf("获取用户信息出现异常了, err: %v", err))
		return nil, status.Error(codes.Internal, "获取用户信息出现异常了")
	}

	if user == nil {
		return nil, status.Error(codes.InvalidArgument, "用户不存在")
	}

	err = u.userDao.UpdateUserById(ctx, user.Id, map[string]interface{}{
		"password":   utils.Base64Md5(in.NewPassword + user.Salt),
		"updated_at": time.Now(),
	})

	if err != nil {
		u.svcCtx.ZapLog.Error(fmt.Sprintf("重置密码失败, err: %v", err))
		return nil, status.Error(codes.Internal, "重置密码失败")
	}

	return &emptypb.Empty{}, nil
}

// MatchUserPassword
// @Description: 账户和密码匹配
// @receiver u
// @param ctx
// @param in
// @return *userServiceV1.UserResponse
// @return error
func (u *UserService) MatchUserPassword(ctx context.Context, in *userServiceV1.MatchUserPasswordRequest) (*userServiceV1.UserResponse, error) {

	if strings.TrimSpace(in.Username) == "" {
		return nil, status.Error(codes.InvalidArgument, "用户名不能为空")
	}

	if strings.TrimSpace(in.Password) == "" {
		return nil, status.Error(codes.InvalidArgument, "密码不能为空")
	}

	user, err := u.userDao.FindByName(ctx, in.Username)
	if err != nil {
		u.svcCtx.ZapLog.Error(fmt.Sprintf("获取用户信息出现异常了, err: %v", err))
		return nil, status.Error(codes.Internal, "获取用户信息出现异常了")
	}

	if user == nil {
		return nil, status.Error(codes.InvalidArgument, "用户不存在")
	}

	if user.Password != utils.Base64Md5(in.Password+user.Salt) {
		return nil, status.Error(codes.InvalidArgument, "密码不正确")
	}

	var userResp userServiceV1.UserResponse
	_ = copier.Copy(&userResp, user)

	return &userResp, nil
}
